#include "TextUtil.h"

TextUtil::TextUtil()
{
}

TextUtil::~TextUtil()
{
}

std::string TextUtil::GetGuid()
{
	boost::uuids::random_generator randomg;
	boost::uuids::uuid cid = randomg();
	std::string strGuid = boost::uuids::to_string(cid);
	boost::algorithm::replace_all(strGuid, "-", "");
	return strGuid;
}

std::string TextUtil::ReplaceAll(std::string& str, const std::string& old_value, const std::string& new_value)
{
	while (true)
	{
		std::string::size_type pos(0);
		if ((pos = str.find(old_value)) != std::string::npos)
			str.replace(pos, old_value.length(), new_value);
		else
			break;
	}
	return str;
}

std::string TextUtil::FormatJson(std::string json)
{
	// 替换libcurl生成的转义字符
	std::string strUtf8 = json;
	strUtf8 = ReplaceAll(strUtf8, "\\n\\t", "");
	strUtf8 = ReplaceAll(strUtf8, "\\n", "");
	strUtf8 = ReplaceAll(strUtf8, "\\\"", "\"");
	strUtf8 = ReplaceAll(strUtf8, "\"[\"", "[");
	strUtf8 = ReplaceAll(strUtf8, "\"]\"", "]");
	//strUtf8 = ReplaceAll(strUtf8, "\"[", "[");
	//strUtf8 = ReplaceAll(strUtf8, "]\"", "]");
	strUtf8 = ReplaceAll(strUtf8, "\"{", "{");
	strUtf8 = ReplaceAll(strUtf8, "}\"", "}");
	strUtf8 = ReplaceAll(strUtf8, "\\n", "");
	return strUtf8;
}

std::string TextUtil::GetRandomAsciiString(int length, bool allowStartByDigit)
{
	std::string result = "";
	std::string hold = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

	srand((unsigned int)time(NULL));

	// 获取长度为n的字符串
	for (int i = 0; i < length; ) {
		// 获取范围之内的索引值
		int index = rand() % hold.length();
		// 是否允许数字大头
		if (!allowStartByDigit && (hold.at(index) >= '0' && hold.at(index) <= '9')) {
			continue;
		}
		result += hold.at(index);
		i++;
	}
	return result;
}

std::string TextUtil::GetRandomDigitString(int length)
{
	std::string result = "";
	std::string hold = "0123456789";
	srand((unsigned int)time(NULL));

	// 获取长度为n的字符串
	for (int i = 0; i < length; ) {
		// 获取范围之内的索引值
		int index = rand() % hold.length();
		result += hold.at(index);
		i++;
	}
	return result;
}

std::string TextUtil::GetTicketTimeString(int random)
{
	uint64_t time = 0;
#ifdef WIN32
	time = GetTickCount64();
#else
	struct timeval tv;
	gettimeofday(&tv, NULL);
	time = (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000;
#endif

	std::string valueStr = boost::lexical_cast<std::string>(time);
	return valueStr + GetRandomDigitString(5);
}

std::string TextUtil::ToLowerCase(std::string source)
{
	std::string dest = "";
	for (int i = 0; i < source.length(); ++i)
	{
		if (source.at(i) >= 'A' && source.at(i) <= 'Z')
		{
			dest += char(int(source.at(i)) + 32);
		}
		else
		{
			dest += source.at(i);
		}
	}
	return dest;
}

std::string TextUtil::ToUpperCase(std::string source)
{
	std::string dest = "";
	for (int i = 0; i < source.length(); ++i)
	{
		if (source.at(i) >= 'a' && source.at(i) <= 'z')
		{
			dest += char(int(source.at(i)) - 32);
		}
		else
		{
			dest += source.at(i);
		}
	}
	return dest;
}

std::string TextUtil::GetRelativePath(std::string source, std::string directory)
{
	// 换算为一样的正斜杠路径
	source = ReplaceAll(source, "\\", "/");
	directory = ReplaceAll(directory, "\\", "/");

	std::string dest = "";
	int pos = source.find(directory);
	if (pos != -1)
	{
		dest = source.substr(pos + directory.length());
	}
	return dest;
}

std::wstring TextUtil::Utf82Unicode(const char* source, int code_page)
{
#ifdef WIN32
	// 预转换, 得到所需空间的大小
	int nBufferSize = ::MultiByteToWideChar(code_page, NULL, source, strlen(source), NULL, 0);
	// 声明临时保存变量
	WCHAR* lpwszDest = new WCHAR[nBufferSize + 1];
	if (NULL == lpwszDest) {
		return L"";
	}

	// 转换为宽字节
	::MultiByteToWideChar(code_page, NULL, source, strlen(source), lpwszDest, nBufferSize);
	// 最后加上'\0'
	lpwszDest[nBufferSize] = L'\0';

	// 删除临时空间
	std::wstring wsTemp(lpwszDest);
	delete[]lpwszDest;
	lpwszDest = NULL;
	return wsTemp;
#else
	size_t in_len = strlen(source);
	size_t out_len = 4 * in_len + 1;

	char* psource = (char*)source;
	char* pbuffer = new char[out_len];
	memset(pbuffer, 0, out_len);

	char** pin = &psource;
	char** pout = &pbuffer;

	// UTF-32LE是Unicode 的一种编码方式
	iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
	if (cd == (iconv_t)-1) {
		delete[]pbuffer;
		return std::wstring();
	}

	if (iconv(cd, pin, &in_len, pout, &out_len) == (size_t)-1) {
		delete[]pbuffer;
		iconv_close(cd);
		return std::wstring();
	}
	iconv_close(cd);

	wchar_t* Temp = new wchar_t[out_len];
	mbstowcs(Temp, pbuffer, strlen(pbuffer));

	std::wstring str(Temp);
	delete[]pbuffer;
	delete[]Temp;
	return str;
#endif
}

std::string TextUtil::Unicode2UTF8(const wchar_t* source, int code_page)
{
#ifdef WIN32
	// 预转换, 得到所需空间的大小
	int nBufferSize = ::WideCharToMultiByte(code_page, NULL, source, wcslen(source), NULL, 0, NULL, NULL);

	// 声明临时保存变量
	CHAR* lpszDest = new CHAR[nBufferSize + 1];
	if (NULL == lpszDest) return "";

	// 转换
	::WideCharToMultiByte(code_page, NULL, source, wcslen(source), lpszDest, nBufferSize, NULL, NULL);

	// 最后加上'\0'
	lpszDest[nBufferSize] = '\0';

	std::string sTemp(lpszDest);
	delete[]lpszDest;
	lpszDest = NULL;

	return sTemp;
#else
	char* buffer = new char[wcslen(source)];
	wcstombs(buffer, source, wcslen(source));

	size_t in_len = wcslen(source);
	size_t out_len = in_len;

	char* psource = (char*)buffer;
	char* pbuffer = new char[out_len];
	memset(pbuffer, 0, out_len);

	char** pin = &psource;
	char** pout = &pbuffer;

	// UTF-32LE是Unicode 的一种编码方式
	iconv_t cd = iconv_open("UTF-8", "UTF-32LE");
	if (cd == (iconv_t)-1) {
		delete[]buffer;
		delete[]pbuffer;
		return std::string();
	}

	if (iconv(cd, pin, &in_len, pout, &out_len) == (size_t)-1) {
		delete[]buffer;
		delete[]pbuffer;
		iconv_close(cd);
		return std::string();
	}
	iconv_close(cd);

	std::string str(pbuffer);
	delete[]buffer;
	delete[]pbuffer;
	return str;
#endif
}

std::string TextUtil::Ascii2Utf8(std::string source)
{
	return Ascii2Utf8(source.c_str());
}

std::string TextUtil::Ascii2Utf8(const char* source)
{
#ifdef WIN32
	std::wstring wText = Utf82Unicode(source, CP_ACP);
	std::string strDes = Unicode2UTF8(wText.c_str(), CP_UTF8);
	return strDes;
#else
	// 文件已经是unicode
	return std::string(source);

	// 假设ASCII转UTF-8最多会增加3倍
	size_t in_len = strlen(source);
	size_t out_len = 4 * in_len;

	char* psource = (char*)source;
	char* pbuffer = new char[out_len];
	memset(pbuffer, 0, out_len);

	char** pin = &psource;
	char** pout = &pbuffer;

	iconv_t cd = iconv_open("UTF-8", "ASCII");
	if (cd == (iconv_t)-1) {
		delete[]pbuffer;
		return std::string();
	}

#include <errno.h>
	size_t size = iconv(cd, pin, &in_len, pout, &out_len);
	if (size == -1) {
		int err = errno;
		delete[]pbuffer;
		iconv_close(cd);
		return std::string();
	}
	iconv_close(cd);

	std::string str(pbuffer);
	delete[]pbuffer;
	return str;
#endif
}

std::string TextUtil::Utf82Ascii(std::string source)
{
	return Utf82Ascii(source.c_str());
}

std::string TextUtil::Utf82Ascii(const char* source)
{
#ifdef WIN32
	std::wstring wText = Utf82Unicode(source, CP_UTF8);
	std::string strDes = Unicode2UTF8(wText.c_str(), CP_ACP);
	return strDes;
#else
	// 假设UTF-8转ASCII大小一致
	size_t in_len = strlen(source);
	size_t out_len = in_len;

	char* psource = (char*)source;
	char* pbuffer = new char[out_len];
	memset(pbuffer, 0, out_len);

	char** pin = &psource;
	char** pout = &pbuffer;

	iconv_t cd = iconv_open("ASCII", "UTF-8");
	if (cd == (iconv_t)-1) {
		delete[]pbuffer;
		return std::string();
	}

#include <errno.h>
	size_t size = iconv(cd, pin, &in_len, pout, &out_len);
	if (size == -1) {
		int err = errno;
		delete[]pbuffer;
		iconv_close(cd);
		return std::string();
	}
	iconv_close(cd);

	std::string str(pbuffer);
	delete[]pbuffer;
	return str;
#endif
}

std::vector<std::string> TextUtil::SplitString(std::string str, char delimiter)
{
	std::vector<std::string> result;

	std::stringstream ss(str);
	std::string item;
	while (std::getline(ss, item, delimiter))
	{
		result.push_back(item);
	}

	return result;
}

bool TextUtil::ContainString(std::vector<std::string>& list, std::string item)
{
	size_t count = list.size();
	for (size_t index = 0; index < count; ++index)
	{
		if (item == list[index])
		{
			return true;
		}
	}
	return false;
}

std::string TextUtil::JoinString(std::vector<std::string>& list, std::string delimiter)
{
	std::stringstream ss;
	for (size_t index = 0; index < list.size() - 1; ++index)
	{
		ss << list[index] << delimiter;
	}
	ss << list[list.size() - 1];
	return ss.str();
}

std::string TextUtil::JoinString(std::set<std::string>& list, std::string delimiter)
{
	size_t i = 0;
	std::stringstream ss;
	for (std::set<std::string>::iterator it = list.begin(); it != list.end(); ++it, ++i)
	{
		std::string str = *it;
		ss << str;
		if (i != list.size() - 1)
		{
			ss << delimiter;
		}
	}
	return ss.str();
}

bool TextUtil::EndWith(const std::string& str, const std::string& tail)
{
	return str.compare(str.size() - tail.size(), tail.size(), tail) == 0;
}

bool TextUtil::StartWith(const std::string& str, const std::string& head)
{
	return str.compare(0, head.size(), head) == 0;
}


std::string TextUtil::GetIpFromRtspUrl(std::string input)
{
	// rtsp://admin:dw123456@192.168.12.136/mpeg4/ch1/main/av_stream
	// rtsp://192.168.12.136:554/mpeg4/ch1/main/av_stream
	std::string url = input;
	int pos = url.find("rtsp://");
	if (pos != -1)
	{
		url = url.substr(pos + 7);
	}
	pos = url.find("rtmp://");
	if (pos != -1)
	{
		url = url.substr(pos + 7);
	}
	pos = url.find_first_of("@");
	if (pos != -1)
	{
		url = url.substr(pos + 1);
	}
	pos = url.find_first_of("/");
	if (pos != -1)
	{
		url = url.substr(0, pos);
	}
	pos = url.find_first_of(":");
	if (pos != -1)
	{
		url = url.substr(0, pos);
	}
	return url;
}

std::string TextUtil::GetIpFromRtspUrl(std::string input, int& port)
{
	// rtsp://admin:dw123456@192.168.12.136/mpeg4/ch1/main/av_stream
	// rtsp://192.168.12.136:554/mpeg4/ch1/main/av_stream
	std::string ip;
	port = 554;

	std::string url = input;
	int pos = url.find("rtsp://");
	if (pos != -1)
	{
		url = url.substr(pos + 7);
	}
	pos = url.find("rtmp://");
	if (pos != -1)
	{
		url = url.substr(pos + 7);
	}
	pos = url.find_first_of("@");
	if (pos != -1)
	{
		url = url.substr(pos + 1);
	}
	pos = url.find_first_of("/");
	if (pos != -1)
	{
		url = url.substr(0, pos);
	}

	ip = url;
	pos = url.find_first_of(":");
	if (pos != -1)
	{
		port = atoi(url.substr(pos + 1).c_str());
		url = url.substr(0, pos);
		ip = url;
	}
	return url;
}

std::string TextUtil::GetIpFromWsUrl(std::string input, std::string& ip, int& port)
{
	// ws://127.0.0.1:10000/demon/iot
	ip = "127.0.0.1";
	port = 80;
	std::string end_point = "";

	std::string url = input;
	int pos = url.find("ws://");
	if (pos != -1)
	{
		url = url.substr(pos + 5);
	}
	pos = url.find("wss://");
	if (pos != -1)
	{
		port = 443;
		url = url.substr(pos + 6);
	}
	pos = url.find_first_of("/");
	if (pos != -1)
	{
		end_point = url.substr(pos);
		url = url.substr(0, pos);
	}
	// 127.0.0.1:10000
	ip = url;
	pos = url.find_first_of(":");
	if (pos != -1)
	{
		port = atoi(url.substr(pos + 1).c_str());
		url = url.substr(0, pos);
		ip = url;
	}
	return end_point;
}

std::string TextUtil::Trim(std::string source)
{
	return boost::algorithm::trim_copy(source);
}

std::string TextUtil::GetToken(std::string authorization)
{
	// Basic Bearer 
	authorization = Trim(authorization);
	std::vector <std::string> list = SplitString(authorization, ' ');
	if (list.size() >= 2)
	{
		return Trim(list[1]);
	}
	return "";
}

std::string TextUtil::UrlEncode(const char* str)
{
	static unsigned char enc_tab[] = "0123456789ABCDEF";

	int len = (int)strlen(str);
	int tmp_len = len;
	unsigned char* tmp = (unsigned char*)malloc(len + 1);

	int i, j;
	for (i = 0, j = 0; i < len; i++, j++) {
		tmp[j] = (unsigned char)str[i];
		// 所传的字符不是字母和数字时，也不是_-.
		if (!isalnum(tmp[j]) && strchr("_-.", tmp[j]) == NULL) {
			tmp_len += 3;
			tmp = (unsigned char*)realloc(tmp, tmp_len);
			tmp[j++] = '%';
			tmp[j++] = enc_tab[(unsigned char)str[i] >> 4];
			tmp[j] = enc_tab[(unsigned char)str[i] & 0x0F];
		}
	}

	tmp[j] = '\0';
	std::string result = (const char*)tmp;

	delete[] tmp;
	return result;
}

std::string TextUtil::UrlDecode(const char* str)
{
	static unsigned char dec_tab[256] = {
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,
		 0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	};

	int len = (int)strlen(str);
	char* tmp = (char*)malloc(len + 1);

	int i = 0, pos = 0;
	for (i = 0; i < len; i++) {
		if (str[i] != '%')
			tmp[pos] = str[i];
		/* check boundary */
		else if (i + 2 >= len) {
			/* keep it */
			tmp[pos++] = '%';
			if (++i >= len)
				break;
			tmp[pos] = str[i];
			break;
		}
		else if (isalnum(str[i + 1]) && isalnum(str[i + 2])) {
			tmp[pos] = (dec_tab[(unsigned char)str[i + 1]] << 4)
				+ dec_tab[(unsigned char)str[i + 2]];
			i += 2;
		}
		else {
			tmp[pos] = str[i];
		}
		pos++;
	}

	tmp[pos] = '\0';
	std::string result = tmp;
	delete[] tmp;
	return result;
}

bool TextUtil::IsDigit(std::string source)
{
	try
	{
		std::stod(source);
		return true;
	}
	catch (const std::exception&)
	{
		return false;
	}
}

bool TextUtil::IsInteger(std::string source)
{
	try
	{
		std::stoi(source);
		return true;
	}
	catch (const std::exception&)
	{
		return false;
	}
}